<?php

/**
 * Class QAppDB
 */
class QAppDB
{
    const COL_TYPE_INT = 'INTEGER';
    const COL_TYPE_BIGINT = 'bigint';
    const COL_TYPE_VARCHAR255 = 'VARCHAR(255)';
    const COL_TYPE_TEXT = 'TEXT';
    const COL_TYPE_DOUBLE = 'DOUBLE';

    /**
     * @var
     */
    public $dbType;
    /**
     * @var PDO
     */
    public $link;
    /**
     * @var int
     */
    public $querynum;
    public $database;
    public $DB;
    /**
     * @var PDOStatement
     */
    public $Stmt;
    public $Sql;
    /**  表前缀
     * @var string
     */
    public $tableex = '';
    /**
     * @var array 配置
     */
    private $dbConfig = null;

    /**
     * 初始化，可以在此时传入配置参数，也可在connect时传入配置参数
     * 配置参数可以通过静态方法makeMysqlConfig或makeSqliteConfig生成
     * QAppDB constructor.
     * @param null $dbConfig
     */
    public function __construct($dbConfig = null)
    {
        if ($dbConfig) {
            $this->dbConfig = $dbConfig;
        }
    }

    /**
     * 生成Mysql的配置
     * @param string $host 主机地址
     * @param string $port 端口
     * @param string $user 数据库用户
     * @param string $password 数据库密码
     * @param string $dbname 数据库名，可空
     * @return array
     */
    public static function makeMysqlConfig($host = '127.0.0.1', $port = '3306', $user = 'root', $password = '123456', $dbname = '')
    {
        return array(
            'type' => 'mysql',
            'mysql' => array(
                'host' => $host,
                'port' => $port,
                'user' => $user,
                'password' => $password,
                'dbname' => $dbname
            )
        );
    }

    /**
     * 生成Sqlite的配置
     * @param string $dbfilename 数据库存放的路径及名称
     * @return array
     */
    public static function makeSqliteConfig($dbfilename = 'auto')
    {
        return array(
            'type' => 'sqlite',
            'sqlite' => array(
                'file' => $dbfilename
            ));
    }

    /**
     * @param $config
     * sqlite的配置案例 ["database"=>"sqlite","dbfile"=>"your/path/db.sqlite"]
     * mysql的配置案例 ["database"=>"mysql","dbname"=>"dbname","host"=>"127.0.0.1","port"=>"3306","user"=>"root","password"=>"123456"]
     * @return bool|string
     */
    public function connect($config = null)
    {
        if ($config) {
            $this->dbConfig = $config;
        }

        if (empty($this->dbConfig)) {
            return '没有配置参数';
        }
        $this->querynum = 0;
        $this->database = $this->dbConfig['database'];
        if ($this->dbConfig['database'] == 'sqlitepdo' || $this->dbConfig['database'] == 'sqlite') {
            $this->dbType = "sqlite";
            $dbfile = 'sqlite:' . $this->dbConfig['dbfile'];
            $this->link = new PDO($dbfile);
            return true;
        } elseif ($this->dbConfig['database'] == 'mysqlpdo' || $this->dbConfig['database'] == 'mysql') {
            if (!isset($this->dbConfig['dbname']) || empty($this->dbConfig['dbname'])) {
                $dbinfo = '';
            } else {
                $dbinfo = 'dbname=' . $this->dbConfig['dbname'];
                $this->DB = $this->dbConfig['dbname'];
            }
            $this->dbConfig['hostinfo'] = explode(':', $this->dbConfig['host']);
            if (count($this->dbConfig['hostinfo']) > 1) {
                $this->dbConfig['host'] = $this->dbConfig['hostinfo'][0];
                $this->dbConfig['port'] = $this->dbConfig['hostinfo'][1];
            } else {
                $this->dbConfig['port'] = '3306';
            }
            try {
                @$this->link = new PDO('mysql:host=' . $this->dbConfig['host'] . ';port=' . $this->dbConfig['port'] . ';' . $dbinfo, $this->dbConfig['user'], $this->dbConfig['password'], array(constant('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY') => true));
                $this->query("SET NAMES utf8mb4");
                $this->dbType = "mysql";
                return true;
            } catch (Exception $errinfo) {
                return 'MySQL数据库连接失败';
            }
        } else {
            return '配置了不支持的数据库类型，目前支持mysql和sqlite';
        }
    }

    /**
     * 连接测试
     * @param $site_db
     * @return bool
     */
    public function mysqlTestConnect($site_db)
    {
        try {
            $link = new PDO('mysql:host=' . array_value($site_db, 'host') . ';port=' . array_value($site_db, 'port') . ';', array_value($site_db, 'user'), array_value($site_db, 'password'), array(constant('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY') => true));
            $link->query("SET NAMES utf8mb4");
            return true;
        } catch (Exception $errinfo) {
            return false;
        }
    }

    /**
     * mysql创建数据库
     * @param $mysql_dbname
     * @return bool
     */
    public function creatMysqlDatabase($mysql_dbname)
    {
        if (!$mysql_dbname) {
            $this->errorMessage("必须输入数据库名");
            return false;
        }
        $this->query('CREATE DATABASE IF NOT EXISTS `' . $mysql_dbname . '` ');
        $alldb = $this->all('SHOW DATABASES');
//        $this->errorMessage($alldb);
        $ifin = 0;
        foreach ($alldb as $val) {
            if ($val['Database'] == $mysql_dbname) {
                $ifin = 1;
                break;
            }
        }

        if ($ifin) {
            $this->link->exec("use " . $mysql_dbname);
            return true;
        }

        $this->errorMessage("未创建数据库，请确定您登录的mysql账户有创建数据库的权限");
        return false;
    }

    /**
     * 获取执行错误信息
     * @param null $_msg
     * @return bool
     */
    public function errorMessage($_msg = null)
    {
        if (!$_msg) {
            $msg = $this->link->errorInfo();
        } else {
            $msg = $_msg;
        }
        if (DEBUG) {
            echo('<pre style="color: red">');
            print_r($msg);
            echo('</pre>');
        }
        return false;
    }


    /**
     * 执行sql查询
     * @param $sql string 语句，支持?或:xx作为占位符
     * @param null $paramsArray 参数，可空，采用数组[5]或键值对[":id"=>5]方式，取决于你用的占位符
     * @return $this|bool
     */
    public function query($sql, $paramsArray = null)
    {
//        dump_pre($sql);
//        exit();
        $this->querynum++;
        if (is_array($paramsArray)) {
            $stem = $this->link->prepare($sql);
            try {
                $ret = $stem->execute($paramsArray);
            } catch (Exception $e) {
                if (function_exists('log_error')){
                    log_error($e->getCode(),$e->getMessage(),$e->getFile(),$e->getLine());
                }
                $ret = false;
            }

            if ($ret) {
                $res = $stem;
            } else {
                $res = false;
            }
        } else {
            try {
                $res = $this->link->query($sql);
            } catch (Exception $e) {
                $res = false;
                if (function_exists('log_error')){
                    log_error($e->getCode(),$e->getMessage(),$e->getFile(),$e->getLine());
                }
            }
        }

        if ($res) {
            $this->Stmt = $res;
            $this->Sql = $sql;
            return $this;
        }
//        $this->errorMessage();

        return false;
    }

    /**
     * 获取所有数据
     * @param string $sql sql语句
     * @param null $paramsArray
     * @return mixed
     */
    public function all($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchAll();
    }

    /**
     * @param $sql
     * @param null $paramsArray
     * @return mixed
     */
    public function all_num($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchAllNum();
    }

    /**
     * 通过SQL查询数据，返回数组
     * @param $sql
     * @param null $paramsArray
     * @return array
     */
    public function all_assoc($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchAllAssoc();
    }

    /**
     * 以关联数组（键值对）的形式返回数据
     * @param $sql
     * @param null $paramsArray
     * @return mixed
     */
    public function one_assoc($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchOneAssoc();
    }

    /**
     * 查询一条数据，会以数字索引和关联数组混合在一起返回
     * @param $sql "select * from admin where id=?"
     * @param null $paramsArray 参数，可空，如[5]
     * @return mixed
     */
    public function one($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchOne();
    }

    /**
     * 查询数量
     * @param $sql
     * @param null $paramsArray
     * @return mixed
     */
    public function fetchcount($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        $res = $this->fetchOneNum();
        if ($res) {
            return $res[0];
        }
        return 0;
    }


    /**
     * 执行sql语句
     * @param $sql
     * @return string
     */
    public function exec($sql)
    {
        if ($this->link->exec($sql)) {
            $this->Sql = $sql;
            return $this->lastId();
        }
        return false;
//        $this->errorMessage();
    }


    /**
     * 对查询返回数据结构化为数组
     * @return mixed
     */
    public function fetchAll()
    {
        return @$this->Stmt->fetchAll(PDO::FETCH_BOTH);
    }

    /**
     * 创建表
     * @param $tablename
     * @param string $PRIMARY_KEY 主键
     * @return bool
     */
    public function creatTable($tablename, $PRIMARY_KEY = 'id')
    {
        $tablename = $this->tablepre($tablename);
        //创建表
        if ($this->dbType == 'sqlite') {
            $ret = $this->query("CREATE TABLE if not exists [" . $tablename . "] ([{$PRIMARY_KEY}] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)");
            return $ret ? true : false;
        } elseif ($this->dbType == 'mysql') {
            $tableMysqlEngine = 'innodb';
            $ret = $this->query("CREATE TABLE if not exists `{$tablename}` (`{$PRIMARY_KEY}` int NOT NULL auto_increment ,PRIMARY KEY  (`{$PRIMARY_KEY}`)) ENGINE=" . $tableMysqlEngine . " DEFAULT CHARSET=utf8mb4;");
            return $ret ? true : false;
        } else {
            return false;
        }
    }

    /**
     * 添加表前缀
     * @param string $table
     * @return string
     */
    public function tablepre($table = '')
    {
        if (substr($table, 0, strlen($this->tableex)) == $this->tableex) {
            return $table;
        } else {
            return $this->tableex . $table;
        }
    }

    /**
     * 插入列
     * @param string $table_name 表名
     * @param string $col_name 列名
     * @param string $col_type 类型，请使用db::COL_获取
     */
    public function addColumn($table_name, $col_name, $col_type)
    {
        $this->query("alter table {$table_name} add {$col_name} {$col_type} NULL;");
    }

    /**
     * @param $sql
     * @param null $paramsArray
     * @return mixed
     */
    public function one_array($sql, $paramsArray = null)
    {
        $this->query($sql, $paramsArray);
        return $this->fetchOneNum();
    }

    /**
     * 获取第一条数据，并结构化为数组
     * @return mixed
     */
    public function fetchOneNum()
    {
        return @$this->Stmt->fetch(PDO::FETCH_NUM);
    }

    /**
     * 对查询返回数据结构化为数组
     * @return mixed
     */
    public function fetchAllNum()
    {
        return @$this->Stmt->fetchAll(PDO::FETCH_NUM);
    }

    /**
     *
     * @param $select
     * @param $table
     * @param $query
     * @param null $paramsArray
     * @return array
     */
    public function select($select, $table, $query, $paramsArray = null)
    {
        $table = $this->tablepre($table);
        return $this->all_assoc("select {$select} from {$table} {$query}", $paramsArray);
    }


    /**
     * 以关联数组形式获取查询结果
     * @return array
     */
    public function fetchAllAssoc()
    {
        return @$this->Stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * 查询一条数据
     * @param $select
     * @param $table
     * @param $query
     * @param null $paramsArray
     * @return mixed
     */
    public function select_one($select, $table, $query, $paramsArray = null)
    {
        $table = $this->tablepre($table);
        return $this->one_assoc("select {$select} from {$table} {$query}", $paramsArray);
    }

    /**
     * 获取第一条数据，并结构化为关联数组
     * @return mixed
     */
    public function fetchOneAssoc()
    {
        return @$this->Stmt->fetch(PDO::FETCH_ASSOC);
    }


    /**
     * 获取第一条数据，并结构化为数组
     * @return mixed
     */
    public function fetchOne()
    {
        return @$this->Stmt->fetch(PDO::FETCH_BOTH);
    }

    /**
     * 查询记录条数
     * @param $table
     * @param $query
     * @param null $paramsArray
     * @return mixed
     */
    public function select_count($table, $query, $paramsArray = null)
    {
        $table = $this->tablepre($table);
        return $this->fetchcount("select count(id) from {$table}  {$query}", $paramsArray);
    }


    /**
     * 删除数据
     * @param string $table 表
     * @param string $where 删除条件，id=5，或id=?,或id=:id
     * @param null $paramsArray 参数，可空，如[5],或 [":id"=>5]
     * @return int|mixed 返回影响行数，如果未删除数据，返回0
     */
    public function del($table, $where, $paramsArray = null)
    {
        if ($where) $where = ' where ' . $where;
        $table = $this->tablepre($table);
        $stem = $this->query("DELETE FROM {$table} {$where}", $paramsArray);
        if ($stem !== false) {
            return $stem->affectRows();
        }
        return 0;
    }

    /**
     * 影响行数
     * @return mixed
     */
    public function affectRows()
    {
        return $this->Stmt->rowCount();
    }

    /**
     * 更新数据
     * @param string $table 表
     * @param string $where 条件
     * @param array $array 更新的键值对数据，键名必须在数据库中存在，键名为"sql"，则值不会转义，可用于["sql"=>"click=click+1"]这种情况
     * @return bool
     */
    public function update($table, $where, $array)
    {
        if ($table == '') {
            return false;
        }
        $table = $this->tablepre($table);
        if (!is_array($array)) {
            return false;
        }
        $str = '';
        foreach ($array as $key => $val) {
            if ($key == "sql") {
                $str .= ',' . $val;
            } elseif (substr($val, 0, 1) == '{' && substr($val, strlen($val) - 1, 1) == '}' && strlen($val) < 20) {
                $val = ltrim($val, '{');
                $val = rtrim($val, '}');
                $str .= ',' . $key . "=" . addslashes($val);
            } else {
                $str .= ',' . $key . "='" . addslashes($val) . "'";
            }
        }
        $str = ltrim($str, ',');
        //echo 'UPDATE ' . $table . ' SET ' . $str . ' WHERE ' . $where;
        if ($this->query('UPDATE ' . $table . ' SET ' . $str . ' WHERE ' . $where)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 最后插入的id
     * @return string
     */
    public function lastId()
    {
        return $this->link->lastInsertId();
    }

    /**
     * @param string $path
     * @return string
     */
    public function backup_only_data($path = '')
    {
        return $this->backup($path, false, true);
    }

    /**
     * 备份数据库
     * @param string $path
     * @param bool $createTable
     * @param bool $data
     * @return string
     */
    public function backup($path = '', $createTable = true, $data = true)
    {
        if ($path) {
            if (!file_exists($path)) {
                file_mkdirs($path, 0777);
            }
        } else {
            $path = DBDir . 'backup/';
            if (!file_exists($path)) mkdir($path, 0777);
        }

        $ouput_file = $path . $this->dbType . "_" . date('Ymd_His') . ".sql";
        $tables = $this->getTables();
        /*sql按表输出到文件*/
        foreach ($tables as $table) {
            //此表为结构表，不需要备份
            if ($table != "sqlite_sequence" && $table != "sqlite_master") {
                $this->ouputToFile($table, $ouput_file, $createTable, $data);
            }
        }

        return $ouput_file;
    }

    /**
     * 获取数据库中的表
     * @return array
     */
    public function getTables()
    {
        $tables = array();
        if ($this->dbType == "sqlite" || $this->dbType == "sqlitepdo") {
            $sth = $this->link->query("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
        } else {
            $sth = $this->link->query('SHOW TABLES');
        }
        while ($row = $sth->fetch()) {
            if ($row[0] != "sqlite_sequence" && $row[0] != "sqlite_master")
                $tables[] = $row[0];
        }
        return $tables;
    }

    /**
     * sql按表输出到文件
     * @param string $table 表
     * @param string $file 存储到文件
     * @param bool $createTable 是否包含创建表的语句
     * @param bool $data 是否导出数据
     */
    private function ouputToFile($table, $file, $createTable = true, $data = true)
    {
        $sql = '';

        /*头注释*/
        $sql .= "-- --------------------------------------------------\n";
        $sql .= "--          Table " . $table . "\n";
        $sql .= "-- --------------------------------------------------\n\n";

        if ($createTable) {
            /*删除已存在的数据表*/
            $sql .= 'DROP TABLE IF EXISTS `' . $table . '`;';
            $sql .= "\n\n";

            /*获取建表语句*/
            $create_sql = $this->getTableDLL($table);
            $sql .= $create_sql['sql'];
            $sql .= ";\n\n";
        }

        if ($data) {
            /*导出数据*/
            /*可以优化为1000条取一次，降低数据量大时的负载*/
            $sth = $this->link->query('SELECT * FROM ' . $table);
            while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
                $sql .= 'INSERT INTO `' . $table . '` VALUES(';
                $fields = [];
                foreach ($row as $field) {
                    if (null !== $field) {
                        $fields[] = $this->link->quote($field);
                    } else {
                        $fields[] = ' null';
                    }
                }
                $sql .= implode(',', $fields);
                $sql .= ");\n";
            }
        }

        $sql .= "\n\n";
        /**
         * 写入文件
         */
        file_put_contents($file, $sql, FILE_APPEND);
    }

    /**
     * 获取表结构
     * @param $tablename
     * @return bool|mixed
     */
    public function getTableDLL($tablename)
    {
        if ($this->dbType == 'sqlite') {
            $this->query("SELECT * FROM sqlite_master WHERE type='table' and name='" . $tablename . "';");
            return $this->fetchOne();
        } elseif ($this->dbType == 'mysql') {
            $ret = $this->query("SHOW CREATE TABLE `{$tablename}`");
            if ($ret) {
                $ret = $this->fetchOne();
                $tableinfo['type'] = 'table';
                $tableinfo['name'] = $tablename;
                $tableinfo['sql'] = $ret['Create Table'];
                return $tableinfo;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * @param $table
     */
    public function dropTable($table)
    {
        $this->query("DROP TABLE IF EXISTS `' . $table . '`;");
    }

    /**
     * 备份为无数据的sql
     * @param string $path
     * @return string 路径
     */
    public function backup_no_data($path = '')
    {
        return $this->backup($path, true, false);
    }

    /**
     * @param string $path
     * @return string
     */
    public function backup_data_json($path = '')
    {
        if ($path) {
            if (!file_exists($path)) {
                file_mkdirs($path, 0777);
            }
        } else {
            $path = DBDir . 'backup/';
            if (!file_exists($path)) mkdir($path, 0777);
        }
        $ouput_file = $path . $this->dbType . "_" . date('Ymd_His') . ".json";

        $tables = $this->getTables();
        $rows = array();
        foreach ($tables as $table) {
            $this->query("select * from {$table}");
            $rows[$table] = $this->fetchAllAssoc();
        }

        file_put_contents($ouput_file, json_encode($rows));
        return $ouput_file;
    }

    /**
     * 保存数据库结构为json格式
     * @param string $path
     * @return string
     */
    public function backup_DDL_json($path = '')
    {
        if ($path) {
            if (!file_exists($path)) {
                file_mkdirs($path, 0777);
            }
        } else {
            $path = DBDir . 'backup/';
            if (!file_exists($path)) mkdir($path, 0777);
        }

        $ouput_file = $path . $this->dbType . "_" . date('Ymd_His') . ".ddl.json";
        $tables = $this->getTables();

        $all_tables = array();
        /*json按表输出到文件*/
        foreach ($tables as $table) {
            //此表为结构表，不需要备份
            if ($table != "sqlite_sequence" && $table != "sqlite_master") {
                $table_columns = $this->getTableColumns($table);
                $all_tables[$table] = $table_columns;
            }
        }

        file_put_contents($ouput_file, json_encode($all_tables));
        return $ouput_file;
    }

    /**
     * 获取表的字段，包含，字段名称，字段类型，其他信息不包含，方便跨mysql和sqilte
     * @param $tablename
     * @return array|bool
     */
    public function getTableColumns($tablename)
    {
        if ($this->dbType == 'mysql') {
            $this->query("show full fields from {$tablename};");
            $tableRows = $this->fetchAllAssoc();

            $columns = array();
            foreach ($tableRows as $row) {
                $columns[] = array('name' => $row['Field'], 'type' => $row['Type']);
            }

            return $columns;
        } elseif ($this->dbType = 'sqlite') {
            $this->query("PRAGMA table_info('{$tablename}')");
            $tableRows = $this->fetchAllAssoc();

            $columns = array();
            foreach ($tableRows as $row) {
                $columns[] = array('name' => $row['name'], 'type' => $row['type']);
            }

            return $columns;
        } else {
            return false;
        }
    }

    /**
     * 从json恢复数据
     * @param string $tableEx
     * @param string $jsonfile
     * @return bool
     */
    public function restore_data_from_json($tableEx, $jsonfile)
    {
        if (!file_exists($jsonfile)) {
            $this->errorMessage('JSON文件不存在！');
            return false;
        }
        $jsonStr = file_get_contents($jsonfile);
        $json = json_decode($jsonStr, 1);
        $this->begin();
        foreach ($json as $table => $rows) {
            foreach ($rows as $row) {
                $this->insert($tableEx . $table, $row);
            }
        }
        return $this->commit();
    }

    /**
     * 开始事务
     * @return bool
     */
    public function begin()
    {
        return $this->link->beginTransaction();
    }

    /**
     * 插入数据
     * @param string $table 表
     * @param array $array 数据，键值对，键必须在表中存在
     * @return bool|string 成功返回插入后的id，失败返回false
     */
    public function insert($table, $array)
    {
        if ($table == '') {
            return false;
        }
        $table = $this->tablepre($table);
        if (!is_array($array)) {
            return false;
        }
        $str1 = array();
        $str2 = array();
        $vals = array();
        foreach ($array as $key => $val) {
            $str1[] = '`' . $key . '`';
            $str2[] = "?";
            $vals[] = $val;
        }
        $str1Str = join(',', $str1);
        $str2Str = join(',', $str2);

        $stem = $this->link->prepare("INSERT INTO `{$table}` ({$str1Str}) VALUES ({$str2Str})");

        if ($stem->execute($vals)) {
            return $this->lastId();
        } else {
            return false;
        }
    }

    /**
     * 提交事务
     * @return bool 成功为true，失败为false
     */
    public function commit()
    {
        return $this->link->commit();
    }

    /**
     * 从SQL文件还原数据库
     * @param string $file 文件路径
     * @return bool
     */
    public function restore($file)
    {
        /*获取SQL*/
        if (!file_exists($file)) {
            $this->errorMessage('SQL文件不存在！');
            return false;
        }
        $sql = file_get_contents($file);
        $sql = str_replace("\r", "\n", $sql);
        $sql = trim($sql);
        $sql_arr = explode("\n", $sql);

        //先消除--注释
        $sql_arr = array_filter($sql_arr, function ($data) {
            $data = trim($data);
            if (empty($data) || preg_match('/^--.*/', $data) || preg_match('/^#.*/', $data)) {
                return false;
            } else {
                return true;
            }
        });
        $sql = implode("\n", $sql_arr);
        //删除/**/注释
        $sql = preg_replace('/\/\*.*\*\//', '', $sql);
        $sql_arr = explode(";\n", $sql);

        if (false === $sql_arr) {
            return false;
        }

        /*循环执行*/
        foreach ($sql_arr as $sql) {
            if (!trim($sql, ";\t\n\r\0\x0B")) continue;
            if (!$this->link->exec($sql)) {
                if ("00000" != $this->link->errorCode()) {
                    $err = $this->link->errorInfo();
                    $this->errorMessage($err[0] . " " . $err[1] . " " . $err[2]);
                    break;
                }
            }
        }
        return true;
    }

    /**
     * 析构方法
     */
    public function __destruct()
    {
        $this->disconnect();
    }

    /**
     * 断开
     */
    public function disconnect()
    {
        $this->DB = null;
        $this->Stmt = null;
    }
}